/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License");  you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * http//www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is ART Ontology API.
 *
 * The Initial Developer of the Original Code is University of Roma Tor Vergata.
 * Portions created by University of Roma Tor Vergata are Copyright (C) 2009.
 * All Rights Reserved.
 *
 * The ART Ontology API were developed by the Artificial Intelligence Research Group
 * (art.uniroma2.it) at the University of Roma Tor Vergata
 * Current information about the ART Ontology API can be obtained at 
 * http//art.uniroma2.it/owlart
 *
 */

/*
 * Contributor(s): Armando Stellato stellato@info.uniroma2.it
 */
package it.uniroma2.art.owlart.models.impl;

import it.uniroma2.art.owlart.exceptions.ModelAccessException;
import it.uniroma2.art.owlart.exceptions.ModelUpdateException;
import it.uniroma2.art.owlart.model.ARTBNode;
import it.uniroma2.art.owlart.model.ARTLiteral;
import it.uniroma2.art.owlart.model.ARTNode;
import it.uniroma2.art.owlart.model.ARTResource;
import it.uniroma2.art.owlart.model.ARTStatement;
import it.uniroma2.art.owlart.model.ARTURIResource;
import it.uniroma2.art.owlart.model.NodeFilters;
import it.uniroma2.art.owlart.models.BaseRDFTripleModel;
import it.uniroma2.art.owlart.models.OWLModel;
import it.uniroma2.art.owlart.models.OWLReasoner;
import it.uniroma2.art.owlart.navigation.ARTLiteralIterator;
import it.uniroma2.art.owlart.navigation.ARTNodeIterator;
import it.uniroma2.art.owlart.navigation.ARTResourceIterator;
import it.uniroma2.art.owlart.navigation.ARTStatementIterator;
import it.uniroma2.art.owlart.navigation.ARTURIResourceIterator;
import it.uniroma2.art.owlart.navigation.RDFIterator;
import it.uniroma2.art.owlart.navigation.RDFIteratorImpl;
import it.uniroma2.art.owlart.utilities.RDFIterators;
import it.uniroma2.art.owlart.vocabulary.OWL;
import it.uniroma2.art.owlart.vocabulary.RDF;
import it.uniroma2.art.owlart.vocabulary.RDFS;
import it.uniroma2.art.owlart.vocabulary.XmlSchema;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OWLModelImpl extends RDFSModelImpl implements OWLModel, OWLReasoner {

	protected static Logger logger = LoggerFactory.getLogger(OWLModelImpl.class);

	private boolean owlThingMaterialization;
	private boolean transitiveReasoning;
	private boolean inverseReasoning;
	private boolean symmetricReasoning;

	public OWLModelImpl(BaseRDFTripleModel baseRep) {
		super(baseRep);

		// REASONING CONFIGURATION
		if (baseRep instanceof OWLReasoner) {
			logger.info("baseModel is an instance of: " + OWLReasoner.class);
			owlThingMaterialization = ((OWLReasoner) baseRep).supportsOWLThingMaterialization();
			transitiveReasoning = ((OWLReasoner) baseRep).supportsTransitiveProperties();
			inverseReasoning = ((OWLReasoner) baseRep).supportsInverseProperties();
			symmetricReasoning = ((OWLReasoner) baseRep).supportsSymmetricProperties();
		} else {
			logger.info("baseModel is NOT an instance of: " + OWLReasoner.class);
			owlThingMaterialization = false;
			transitiveReasoning = false;
			inverseReasoning = false;
			symmetricReasoning = false;
		}
		logger.info(OWLModelImpl.class + " loaded, reasoning settings:\n" + "owlThingMaterialization: "
				+ owlThingMaterialization + "\ntransitiveReasoning: " + transitiveReasoning
				+ "\ninverseReasoning: " + inverseReasoning + "\nsymmetricReasoning: "
				+ symmetricReasoning);
	}

	/****************************
	 * /* ADD/REMOVE METHODS ***
	 ****************************/

	public void addAnnotationProperty(String propertyURI, ARTURIResource superProperty, ARTResource... graphs)
			throws ModelUpdateException {
		ARTURIResource newProp = baseRep.createURIResource(propertyURI);
		baseRep.addTriple(newProp, RDF.Res.TYPE, OWL.Res.ANNOTATIONPROPERTY, graphs);
		if (superProperty != null)
			baseRep.addTriple(newProp, RDFS.Res.SUBPROPERTYOF, superProperty, graphs);
	}

	public void addDatatypeProperty(String propertyURI, ARTURIResource superProperty, ARTResource... graphs)
			throws ModelUpdateException {
		ARTURIResource newProp = baseRep.createURIResource(propertyURI);
		baseRep.addTriple(newProp, RDF.Res.TYPE, OWL.Res.DATATYPEPROPERTY, graphs);
		if (superProperty != null)
			baseRep.addTriple(newProp, RDFS.Res.SUBPROPERTYOF, superProperty, graphs);
	}

	public void addObjectProperty(String propertyURI, ARTURIResource superProperty, ARTResource... graphs)
			throws ModelUpdateException {
		ARTURIResource newProp = baseRep.createURIResource(propertyURI);
		baseRep.addTriple(newProp, RDF.Res.TYPE, OWL.Res.OBJECTPROPERTY, graphs);
		if (superProperty != null)
			baseRep.addTriple(newProp, RDFS.Res.SUBPROPERTYOF, superProperty, graphs);
	}

	public void addOntologyProperty(String propertyURI, ARTURIResource superProperty, ARTResource... graphs)
			throws ModelUpdateException {
		ARTURIResource newProp = baseRep.createURIResource(propertyURI);
		baseRep.addTriple(newProp, RDF.Res.TYPE, OWL.Res.ONTOLOGYPROPERTY, graphs);
		if (superProperty != null)
			baseRep.addTriple(newProp, RDFS.Res.SUBPROPERTYOF, superProperty, graphs);
	}

	public void addImportStatement(String baseURI, ARTResource... contexts) throws ModelUpdateException {
		ARTURIResource importedRes = baseRep.createURIResource(baseURI);
		baseRep.addTriple(baseRep.createURIResource(getBaseURI()), OWL.Res.IMPORTS, importedRes, contexts);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.uniroma2.art.ontapi.repository.impl.ARTRDFSRepositoryImpl#addNewClass(java.lang.String)
	 * 
	 * while the RDFS adds a rdfs:Class, this one adds an owl:Class
	 */
	@Override
	public void addClass(String uri, ARTResource... contexts) throws ModelUpdateException {
		ARTURIResource newClass = baseRep.createURIResource(uri);
		baseRep.addTriple(newClass, RDF.Res.TYPE, OWL.Res.CLASS, contexts);
	}

	public void removeImportStatement(ARTURIResource URI, ARTResource... contexts)
			throws ModelUpdateException {
		baseRep.deleteTriple(baseRep.createURIResource(getBaseURI()), OWL.Res.IMPORTS, URI, contexts);
	}

	public void addValuesToDatarange(ARTResource dataRange, Iterator<ARTLiteral> literals,
			ARTResource... graphs) throws ModelAccessException, ModelUpdateException {
		// check if the datarange has no associated values
		ARTStatement statement = baseRep.createStatement(dataRange, OWL.Res.ONEOF, RDF.Res.NIL);
		if (baseRep.hasStatement(statement, true, graphs)) {
			// the datarange has no associated value
			baseRep.deleteStatement(statement, graphs);
			ARTBNode tempList = baseRep.createBNode();
			if (literals.hasNext()) {
				baseRep.deleteStatement(statement, graphs);
				baseRep.addTriple(dataRange, OWL.Res.ONEOF, tempList, graphs);
				ARTLiteral lit = literals.next();
				baseRep.addTriple(tempList, RDF.Res.FIRST, lit, graphs);
			}
			while (literals.hasNext()) {
				ARTLiteral lit = literals.next();
				ARTBNode newTempList = baseRep.createBNode();
				baseRep.addTriple(newTempList, RDF.Res.FIRST, lit, graphs);
				baseRep.addTriple(tempList, RDF.Res.REST, newTempList, graphs);
				tempList = newTempList;
			}
			baseRep.addTriple(tempList, RDF.Res.REST, RDF.Res.NIL, graphs);
		} else {
			// the datarange has at least one associated value, so obtain from list the last element
			ARTBNode list = baseRep.listStatements(dataRange, OWL.Res.ONEOF, NodeFilters.ANY, true, graphs)
					.getNext().getObject().asBNode();
			while (true) {
				statement = baseRep.createStatement(list, RDF.Res.REST, RDF.Res.NIL);
				if (baseRep.hasStatement(statement, true, graphs)) {
					// this is the last element, so add the new value after this one
					baseRep.deleteStatement(statement, graphs);
					while (literals.hasNext()) {
						ARTLiteral lit = literals.next();
						ARTBNode newTempList = baseRep.createBNode();
						baseRep.addTriple(newTempList, RDF.Res.FIRST, lit, graphs);
						baseRep.addTriple(list, RDF.Res.REST, newTempList, graphs);
						list = newTempList;
					}
					baseRep.addTriple(list, RDF.Res.REST, RDF.Res.NIL, graphs);
					break;
				}
				list = baseRep.listStatements(list, RDF.Res.REST, NodeFilters.ANY, true, graphs).getNext()
						.getObject().asBNode();
			}
		}
	}

	public void addValueToDatarange(ARTResource dataRange, ARTLiteral lit, ARTResource... graphs)
			throws ModelAccessException, ModelUpdateException {

		// check if the datarange has no associated values
		ARTStatement statement = baseRep.createStatement(dataRange, OWL.Res.ONEOF, RDF.Res.NIL);
		if (baseRep.hasStatement(statement, true, graphs)) {
			// the datarange has no associated value
			baseRep.deleteStatement(statement, graphs);
			ARTBNode tempList = baseRep.createBNode();
			baseRep.addTriple(dataRange, OWL.Res.ONEOF, tempList, graphs);
			baseRep.addTriple(tempList, RDF.Res.FIRST, lit, graphs);
			baseRep.addTriple(tempList, RDF.Res.REST, RDF.Res.NIL, graphs);
		} else {
			// the datarange has at least one associated value, so obtain from list the last element
			ARTBNode list = baseRep.listStatements(dataRange, OWL.Res.ONEOF, NodeFilters.ANY, true, graphs)
					.getNext().getObject().asBNode();
			while (true) {
				statement = baseRep.createStatement(list, RDF.Res.REST, RDF.Res.NIL);
				if (baseRep.hasStatement(statement, true, graphs)) {
					// this is the last element, so add the new value after this one
					baseRep.deleteStatement(statement, graphs);
					ARTBNode tempList = baseRep.createBNode();
					baseRep.addTriple(list, RDF.Res.REST, tempList, graphs);
					baseRep.addTriple(tempList, RDF.Res.FIRST, lit, graphs);
					baseRep.addTriple(tempList, RDF.Res.REST, RDF.Res.NIL, graphs);
					break;
				}
				list = baseRep.listStatements(list, RDF.Res.REST, NodeFilters.ANY, true, graphs).getNext()
						.getObject().asBNode();
			}
		}
	}

	public void removeValueFromDatarange(ARTResource dataRange, ARTLiteral lit, ARTResource... graphs)
			throws ModelAccessException, ModelUpdateException {
		// search inside the values for the desidered ARTLiteral
		ARTStatement statement = baseRep.createStatement(dataRange, OWL.Res.ONEOF, RDF.Res.NIL);
		if (baseRep.hasStatement(statement, true, graphs))
			return; // the datarange has no value
		ARTBNode list = baseRep.listStatements(dataRange, OWL.Res.ONEOF, NodeFilters.ANY, true, graphs)
				.getNext().getObject().asBNode();
		ARTResource prevElem = dataRange;
		while (true) {
			statement = baseRep.createStatement(list, RDF.Res.FIRST, lit);
			if (baseRep.hasStatement(statement, true, graphs)) {
				// the desired value has been found
				ARTResource nextList = baseRep
						.listStatements(list, RDF.Res.REST, NodeFilters.ANY, true, graphs).getNext()
						.getObject().asResource();
				if (prevElem.equals(dataRange))
					baseRep.deleteTriple(prevElem, OWL.Res.ONEOF, list, graphs);
				else
					baseRep.deleteTriple(prevElem, RDF.Res.REST, list, graphs);
				baseRep.deleteTriple(list, NodeFilters.ANY, NodeFilters.ANY, graphs);
				if (prevElem.equals(dataRange))
					baseRep.addTriple(prevElem, OWL.Res.ONEOF, nextList, graphs);
				else
					baseRep.addTriple(prevElem, RDF.Res.REST, nextList, graphs);
				break;
			}
			statement = baseRep.createStatement(list, RDF.Res.REST, RDF.Res.NIL);
			if (baseRep.hasStatement(statement, true, graphs)) {
				// the datarange does not have the desired ARTLiteral
				break;
			}
			prevElem = list;
			list = baseRep.listStatements(list, RDF.Res.REST, NodeFilters.ANY, true, graphs).getNext()
					.getObject().asBNode();
		}
	}

	/**************************************
	 *** TRIPLE INSTANTIATION METHODS ***
	 **************************************/

	public void instantiateDatatypeProperty(ARTResource subject, ARTURIResource predicate,
			String literalString, ARTResource... contexts) throws ModelUpdateException {
		ARTLiteral lit = baseRep.createLiteral(literalString);
		baseRep.addTriple(subject, predicate, lit, contexts);
	}

	public void instantiateObjectProperty(ARTResource subject, ARTURIResource predicate, ARTResource object,
			ARTResource... contexts) throws ModelUpdateException {
		baseRep.addTriple(subject, predicate, object, contexts);
	}

	public void instantiateAnnotationProperty(ARTResource subject, ARTURIResource property, String value,
			String lang, ARTResource... contexts) throws ModelUpdateException {
		ARTLiteral lit = baseRep.createLiteral(value, lang);
		baseRep.addTriple(subject, property, lit, contexts);
	}

	// actually this implementation should be better split up in a centralized method for creating lists, and
	// then the call for this method to link to dataranges
	// even better, RDFIterators could host a method for creating triples, and then another method should
	// write these triples to the store (think we lack of a general method for storing sets of triples or
	// iterators over triples to the triple store
	public String setDataRange(ARTURIResource property, RDFIterator<ARTLiteral> dataRangeIterator,
			ARTResource... graphs) throws ModelAccessException, ModelUpdateException {
		ARTBNode dataRange = baseRep.createBNode();
		ARTBNode tempList = baseRep.createBNode();

		baseRep.addTriple(property, RDFS.Res.RANGE, dataRange, graphs);
		baseRep.addTriple(dataRange, RDF.Res.TYPE, OWL.Res.DATARANGE, graphs);

		// first case: empty list, add nil then immediate exit
		if (!dataRangeIterator.streamOpen()) {
			baseRep.addTriple(dataRange, OWL.Res.ONEOF, RDF.Res.NIL, graphs);
			return dataRange.asBNode().getID();
		}

		// first case, non-empty list
		baseRep.addTriple(dataRange, OWL.Res.ONEOF, tempList, graphs);
		baseRep.addTriple(tempList, RDF.Res.FIRST, dataRangeIterator.getNext(), graphs);

		// iteration
		while (dataRangeIterator.streamOpen()) {
			ARTBNode newTempList = createBNode();
			baseRep.addTriple(tempList, RDF.Res.REST, newTempList, graphs);
			baseRep.addTriple(newTempList, RDF.Res.FIRST, dataRangeIterator.getNext(), graphs);
			tempList = newTempList;
		}
		baseRep.addTriple(tempList, RDF.Res.REST, RDF.Res.NIL, graphs);
		return dataRange.asBNode().getID();
	}

	/*************************
	 *** BOOLEAN METHODS ***
	 *************************/

	public boolean isAnnotationProperty(ARTURIResource prop, ARTResource... contexts)
			throws ModelAccessException {
		return baseRep.hasTriple(prop, RDF.Res.TYPE, OWL.Res.ANNOTATIONPROPERTY, true, contexts);
	}

	public boolean isDatatypeProperty(ARTURIResource prop, ARTResource... contexts)
			throws ModelAccessException {
		return baseRep.hasTriple(prop, RDF.Res.TYPE, OWL.Res.DATATYPEPROPERTY, true, contexts);
	}

	public boolean isOntologyProperty(ARTURIResource prop, ARTResource... graphs) throws ModelAccessException {
		return baseRep.hasTriple(prop, RDF.Res.TYPE, OWL.Res.ONTOLOGYPROPERTY, true, graphs);
	}

	public boolean isFunctionalProperty(ARTURIResource property, ARTResource... contexts)
			throws ModelAccessException {
		return baseRep.hasTriple(property, RDF.Res.TYPE, OWL.Res.FUNCTIONALPROPERTY, true, contexts);
	}

	public boolean isInverseFunctionalProperty(ARTURIResource property, ARTResource... contexts)
			throws ModelAccessException {
		return baseRep.hasTriple(property, RDF.Res.TYPE, OWL.Res.INVERSEFUNCTIONALPROPERTY, true, contexts);
	}

	public boolean isObjectProperty(ARTURIResource property, ARTResource... contexts)
			throws ModelAccessException {
		return baseRep.hasTriple(property, RDF.Res.TYPE, OWL.Res.OBJECTPROPERTY, true, contexts);
	}

	public boolean isSymmetricProperty(ARTURIResource property, ARTResource... contexts)
			throws ModelAccessException {
		return baseRep.hasTriple(property, RDF.Res.TYPE, OWL.Res.SYMMETRICPROPERTY, true, contexts);
	}

	public boolean isTransitiveProperty(ARTURIResource property, ARTResource... contexts)
			throws ModelAccessException {
		return baseRep.hasTriple(property, RDF.Res.TYPE, OWL.Res.TRANSITIVEPROPERTY, true, contexts);
	}

	public boolean isDataRange(ARTResource range, ARTResource... graphs) throws ModelAccessException {
		return baseRep.hasTriple(range, RDF.Res.TYPE, OWL.Res.DATARANGE, true, graphs);
	}

	public boolean isOntology(ARTURIResource uri, ARTResource... contexts) throws ModelAccessException {
		return baseRep.hasTriple(uri, RDF.Res.TYPE, OWL.Res.ONTOLOGY, true, contexts);
	}

	public boolean hasValueInDatarange(ARTResource dataRange, ARTLiteral lit, ARTResource... graphs)
			throws ModelAccessException {
		// search inside the values for the desidered ARTLiteral
		ARTStatement statement = baseRep.createStatement(dataRange, OWL.Res.ONEOF, RDF.Res.NIL);
		if (baseRep.hasStatement(statement, true, graphs))
			return false; // the datarange has no value
		ARTBNode list = baseRep.listStatements(dataRange, OWL.Res.ONEOF, NodeFilters.ANY, true, graphs)
				.getNext().getObject().asBNode();
		while (true) {
			statement = baseRep.createStatement(list, RDF.Res.FIRST, lit);
			if (baseRep.hasStatement(statement, true, graphs)) {
				return true;
			}
			statement = baseRep.createStatement(list, RDF.Res.REST, RDF.Res.NIL);
			if (baseRep.hasStatement(statement, true, graphs)) {
				// the datarange does not have the desired ARTLiteral
				return false;
			}
			list = baseRep.listStatements(list, RDF.Res.REST, NodeFilters.ANY, true, graphs).getNext()
					.getObject().asBNode();
		}
	}

	/*************************
	 *** LIST/GET METHODS ***
	 *************************/

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.uniroma2.art.owlart.models.impl.RDFSModelImpl#listNamedClasses(boolean,
	 * it.uniroma2.art.owlart.model.ARTResource[])
	 * 
	 * NOTE: it is a bare copy of the RDFSModelImpl method implementation, bith the sole addition of owl:Class
	 * for the non-reasoning case
	 */
	public ARTURIResourceIterator listNamedClasses(boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		logger.trace("inside the listNamedClasses of RDFSModel");
		if (inferred && supportsClassIdentification()) {
			logger.trace("this model supports: inferred && supportsSubClassOfClosure()");
			return RDFIterators.filterURIs(RDFIterators.listSubjects(baseRep.listStatements(NodeFilters.ANY,
					RDF.Res.TYPE, RDFS.Res.CLASS, true, graphs)));
		} else {
			// this can actually be improved: if no classIdentification is available, but
			// instanceMaterialization for subclasses is available, we can avoid the look for owl:Class and
			// generate a third if
			logger.trace("this model does not support : supportsClassIdentification(), thus "
					+ "on-the-fly compilation of reasoning consequences is necessary for listing named classes");
			return RDFIterators.listDistinct(RDFIterators.filterURIs(RDFIterators.listSubjects(RDFIterators
					.createARTStatementIterator(RDFIterators.concat(baseRep.listStatements(NodeFilters.ANY,
							RDF.Res.TYPE, OWL.Res.CLASS, inferred, graphs), RDFIterators.concat(baseRep
							.listStatements(NodeFilters.ANY, RDFS.Res.SUBCLASSOF, NodeFilters.ANY, inferred,
									graphs), baseRep.listStatements(NodeFilters.ANY, RDF.Res.TYPE,
							RDFS.Res.CLASS, inferred, graphs)))))));
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.uniroma2.art.owlart.models.impl.RDFSModelImpl#listClasses(boolean,
	 * it.uniroma2.art.owlart.model.ARTResource[])
	 * 
	 * NOTE: it is a bare copy of the RDFSModelImpl method implementation, bith the sole addition of owl:Class
	 * for the non-reasoning case
	 */
	public ARTResourceIterator listClasses(boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		logger.trace("inside the listNamedClasses of RDFSModel");
		if (inferred && supportsClassIdentification()) {
			logger.trace("this model supports: inferred && supportsSubClassOfClosure()");
			return RDFIterators.listSubjects(baseRep.listStatements(NodeFilters.ANY, RDF.Res.TYPE,
					RDFS.Res.CLASS, true, graphs));
		} else {
			// this can actually be improved: if no classIdentification is available, but
			// instanceMaterialization for subclasses is available, we can avoid the look for owl:Class and
			// generate a third if
			logger.trace("this model does not support : supportsClassIdentification(), thus "
					+ "on-the-fly compilation of reasoning consequences is necessary for listing named classes");
			return RDFIterators.listDistinct(RDFIterators.listSubjects(RDFIterators
					.createARTStatementIterator(RDFIterators.concat(baseRep.listStatements(NodeFilters.ANY,
							RDF.Res.TYPE, OWL.Res.CLASS, inferred, graphs), RDFIterators.concat(baseRep
							.listStatements(NodeFilters.ANY, RDFS.Res.SUBCLASSOF, NodeFilters.ANY, inferred,
									graphs), baseRep.listStatements(NodeFilters.ANY, RDF.Res.TYPE,
							RDFS.Res.CLASS, inferred, graphs))))));
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.uniroma2.art.owlart.models.OWLModel#listAnnotationProperties(boolean,
	 * it.uniroma2.art.owlart.model.ARTResource[])
	 */
	public ARTURIResourceIterator listAnnotationProperties(boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		return RDFIterators.toURIResourceIterator(listSubjectsOfPredObjPair(RDF.Res.TYPE,
				OWL.Res.ANNOTATIONPROPERTY, inferred, graphs));
	}

	public ARTURIResourceIterator listDatatypeProperties(boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		return RDFIterators.toURIResourceIterator(listSubjectsOfPredObjPair(RDF.Res.TYPE,
				OWL.Res.DATATYPEPROPERTY, inferred, graphs));
	}

	public ARTURIResourceIterator listObjectProperties(boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		return RDFIterators.toURIResourceIterator(listSubjectsOfPredObjPair(RDF.Res.TYPE,
				OWL.Res.OBJECTPROPERTY, inferred, graphs));
	}

	public ARTURIResourceIterator listOntologyProperties(boolean inferred, ARTResource... graphs)
			throws ModelAccessException {
		return RDFIterators.toURIResourceIterator(listSubjectsOfPredObjPair(RDF.Res.TYPE,
				OWL.Res.ONTOLOGYPROPERTY, inferred, graphs));
	}

	public ARTURIResource getInverseProperty(ARTURIResource objectProperty, boolean inferred,
			ARTResource... graphs) throws ModelAccessException {
		ARTResourceIterator it = listSymmetricPropertyBoundConcepts(objectProperty, OWL.Res.INVERSEOF,
				inferred, graphs);
		if (it.streamOpen())
			return it.getNext().asURIResource();
		else
			return null;
	}

	public ARTURIResourceIterator listOntologyImports(ARTURIResource ontology, ARTResource... contexts)
			throws ModelAccessException {
		return new URIResourceIteratorWrappingNodeIterator(new ObjectsOfStatementsIterator(
				baseRep.listStatements(ontology, OWL.Res.IMPORTS, NodeFilters.ANY, false, contexts)));
	}

	public ARTLiteralIterator listValuesOfSubjDTypePropertyPair(ARTResource instance,
			ARTURIResource property, boolean inferred, ARTResource... contexts) throws ModelAccessException {
		return new LiteralIteratorWrappingNodeIterator(new ObjectsOfStatementsIterator(
				baseRep.listStatements(instance, property, NodeFilters.ANY, inferred, contexts)));
	}

	public ARTResourceIterator listValuesOfSubjObjPropertyPair(ARTResource individual,
			ARTURIResource property, boolean inferred, ARTResource... contexts) throws ModelAccessException {
		return new ResourceIteratorWrappingNodeIterator(new ObjectsOfStatementsIterator(
				baseRep.listStatements(individual, property, NodeFilters.ANY, inferred, contexts)));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.uniroma2.art.ontapi.repository.impl.ARTRDFSRepositoryImpl#retrieveClass(java.lang.String)
	 * 
	 * this implementation tries to makedo with the possibile lackness of a reasoner, so that owl classes
	 * would not be recognized as rdfs classes
	 */
	@Override
	public ARTURIResource retrieveClass(String uri, ARTResource... contexts) throws ModelAccessException {
		ARTStatementIterator statIt = baseRep.listStatements(baseRep.createURIResource(uri), RDF.Res.TYPE,
				RDFS.Res.CLASS, false, contexts);
		if (statIt.streamOpen()) {
			ARTURIResource cls = statIt.next().getSubject().asURIResource();
			statIt.close();
			return cls;
		}

		statIt = baseRep.listStatements(baseRep.createURIResource(uri), RDF.Res.TYPE, OWL.Res.CLASS, false,
				contexts);
		if (statIt.streamOpen()) {
			ARTURIResource cls = statIt.next().getSubject().asURIResource();
			statIt.close();
			return cls;
		}

		return null;
	}

	public ARTLiteralIterator parseDataRange(ARTResource dataRange, ARTResource... graphs)
			throws ModelAccessException {
		ARTResourceIterator resIt = listValuesOfSubjObjPropertyPair(dataRange, OWL.Res.ONEOF, true, graphs);

		if (resIt.streamOpen()) {
			ARTResource oneOfInstance = resIt.getNext();
			resIt.close();
			ARTNodeIterator it = RDFIterators.createRDFListIterator(this, oneOfInstance, true, graphs);
			return RDFIterators.toLiteralIterator(it);
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seeit.uniroma2.art.ontapi.repository.impl.ARTRDFSRepositoryImpl#isClass(it.uniroma2.art.ontapi.model.
	 * ARTResource)
	 * 
	 * this implementation tries to makedo with the possibile lackness of a reasoner, so that owl classes
	 * would not be recognized as rdfs classes
	 * 
	 * NOTE: It is a copy of the implementation in RDFSModelImpl and only adds the check for owl:Class in the
	 * non-reasoning case
	 */
	@Override
	public boolean isClass(ARTResource cls, ARTResource... graphs) throws ModelAccessException {
		logger.trace("inside the isClass of RDFSModel");
		if (supportsClassIdentification()) {
			logger.trace("this model supports: supportsClassIdentification()");
			return baseRep.hasTriple(cls, RDF.Res.TYPE, RDFS.Res.CLASS, true, graphs);
		} else {
			logger.trace("this model does not support supportsClassIdentification, thus "
					+ "on-the-fly compilation of reasoning consequences is necessary for identifying named classes");
			return ((baseRep.hasTriple(cls, RDF.Res.TYPE, OWL.Res.CLASS, true, graphs))
					|| baseRep.hasTriple(cls, RDFS.Res.SUBCLASSOF, NodeFilters.ANY, true, graphs) || (baseRep
						.hasTriple(cls, RDF.Res.TYPE, RDFS.Res.CLASS, true, graphs)));
		}
	}

	public void deleteIndividual(ARTResource res, ARTResource... graphs) throws ModelUpdateException {
		// an individual does not appear as predicate in triples, the same way as a class
		deleteClass(res, graphs);
	}

	public void renameIndividual(ARTURIResource oldIndividual, String newURI, ARTResource... graphs)
			throws ModelUpdateException {
		// an individual does not appear as predicate in triples, the same way as a class
		renameClass(oldIndividual, newURI, graphs);
	}

	/******************************
	 *** OWL REASONING METHODS ***
	 ******************************/

	public boolean supportsOWLThingMaterialization() {
		return owlThingMaterialization;
	}

	public boolean supportsInverseProperties() {
		return inverseReasoning;
	}

	public boolean supportsTransitiveProperties() {
		return transitiveReasoning;
	}

	public boolean supportsSymmetricProperties() {
		return symmetricReasoning;
	}

	/***********************************************
	 *** TRIVIAL OWL REASONING FACILITY METHODS ***
	 ***********************************************/
	// TODO the following methods can be improved by providing look-ahead iterators carrying an hashset with
	// them and filling it progressively (when calls to hasNext are made) to avoid repetitions, instead of
	// filling the whole set and then returning hashSet.iterator();

	/**
	 * this method is invoked by this OWLModel implementation when one needs to known exactly if a triple is
	 * available through inference on property which has an inverse. In this case, if a reasoner is not
	 * available or if it is not able to provide owl:inverseOf computation, then an algorithmic solution is
	 * adopted to provide on-the-fly computation for the property passed as an argument.
	 * 
	 * @param resource
	 * @param property
	 * @param inverseProperty
	 * @param object
	 * @param inferred
	 * @param graphs
	 * @return
	 * @throws ModelAccessException
	 */
	protected boolean hasInversePropertyBoundConcept(ARTResource resource, ARTURIResource property,
			ARTURIResource inverseProperty, ARTResource object, boolean inferred, ARTResource... graphs)
			throws ModelAccessException {

		boolean result = baseRep.hasTriple(resource, property, object, inferred, graphs);

		if (result || !inferred || supportsInverseProperties())
			return result;
		// if i found the result I'm already ok in any case, but if is not, and I want inference and my
		// reasoner does not support inverse properties, then...
		else {
			return baseRep.hasTriple(object, inverseProperty, resource, inferred, graphs);
		}
	}

	/**
	 * this method is invoked by this OWLModel implementation when one needs to known exactly if a triple is
	 * available through inference on property which is symmetric. In this case, if a reasoner is not
	 * available or if it is not able to provide owl:Symmetric computation, then an algorithmic solution is
	 * adopted to provide on-the-fly computation for the property passed as an argument.
	 * 
	 * @param resource
	 * @param property
	 * @param object
	 * @param inferred
	 * @param graphs
	 * @return
	 * @throws ModelAccessException
	 */
	protected boolean hasSymmetricPropertyBoundConcept(ARTResource resource, ARTURIResource property,
			ARTResource object, boolean inferred, ARTResource... graphs) throws ModelAccessException {

		// could also be implemented through hasInversePropertyBoundConcept by using same property as direct
		// and inverse of itself. Use this shortcut if further reengineering is needed

		boolean result = baseRep.hasTriple(resource, property, object, inferred, graphs);

		if (result || !inferred || supportsSymmetricProperties())
			return result;
		// if i found the result I'm already ok in any case, but if is not, and I want inference and my
		// reasoner does not support symmetric properties, then...
		else {
			return baseRep.hasTriple(object, property, resource, inferred, graphs);
		}
	}

	/**
	 * this method is invoked by this OWLModel implementation when one needs to known exactly if a triple is
	 * available through inference on a transitive property. In this case, if a reasoner is not available or
	 * if it is not able to provide owl:inverseOf computation, then an algorithmic solution is adopted to
	 * provide on-the-fly computation for the property passed as an argument.
	 * 
	 * @param resource
	 * @param property
	 * @param object
	 * @param inferred
	 * @param graphs
	 * @return
	 * @throws ModelAccessException
	 */
	protected boolean hasTransitivePropertyBoundConcept(ARTResource resource, ARTURIResource property,
			ARTResource object, boolean inferred, ARTResource... graphs) throws ModelAccessException {
		return hasTransitivePropertyBoundConcept(resource, property, property, object, inferred, graphs);
	}

	/**
	 * * as for
	 * {@link #hasTransitivePropertyBoundConcept(ARTResource, ARTURIResource, ARTResource, boolean, ARTResource...)}
	 * though the transitive property is the transitive extension of a non-transitive property.<br/>
	 * If no reasoning is asked, the non-transitive property is looked in the concrete triples.<br/>
	 * In case of reasoning (inferred==true), if a reasoner is able to compute it (it has transitive property
	 * reasoning), the transitive property is explored, while if it is not, a recursive exploration of the
	 * non-transitive property is conducted
	 * 
	 * @param resource
	 * @param nonTransitiveProperty
	 * @param transitiveExtensionProperty
	 * @param object
	 * @param inferred
	 * @param graphs
	 * @return
	 * @throws ModelAccessException
	 */
	protected boolean hasTransitivePropertyBoundConcept(ARTResource resource,
			ARTURIResource nonTransitiveProperty, ARTURIResource transitiveExtensionProperty,
			ARTResource object, boolean inferred, ARTResource... graphs) throws ModelAccessException {
		if (!inferred)
			return hasTriple(resource, nonTransitiveProperty, object, false, graphs);
		if (supportsTransitiveProperties()) {
			return hasTriple(resource, transitiveExtensionProperty, object, true, graphs);
		} else {
			HashSet<ARTResource> set = new HashSet<ARTResource>();
			return recursiveCheckExploration(set, resource, nonTransitiveProperty, object, graphs);
		}
	}

	/**
	 * @param resource
	 * @param nonTransitiveProperty
	 * @param nonTransitiveInverseProperty
	 *            inverse property of property <code>nonTransitiveProperty</code>
	 * @param transitiveExtensionProperty
	 *            transitive extension of property <code>nonTransitiveProperty</code>
	 * @param transitiveExtensionInverseProperty
	 *            transitive extension of property <code>nonTransitiveInverseProperty</code>
	 * @param object
	 * @param inferred
	 * @param graphs
	 * @return
	 * @throws ModelAccessException
	 */
	protected boolean hasTransitiveInversePropertyBoundConcept(ARTResource resource,
			ARTURIResource nonTransitiveProperty, ARTURIResource nonTransitiveInverseProperty,
			ARTURIResource transitiveExtensionProperty, ARTURIResource transitiveExtensionInverseProperty,
			ARTResource object, boolean inferred, ARTResource... graphs) throws ModelAccessException {

		if (!inferred)
			return hasTriple(resource, nonTransitiveProperty, object, false, graphs);

		if (supportsTransitiveProperties() && supportsInverseProperties()) {
			return hasTriple(resource, transitiveExtensionProperty, object, true, graphs);
		} else if (supportsTransitiveProperties()) {
			return hasInversePropertyBoundConcept(resource, transitiveExtensionProperty,
					transitiveExtensionInverseProperty, object, true, graphs);
		} else if (supportsInverseProperties()) {
			return hasTransitivePropertyBoundConcept(resource, nonTransitiveProperty,
					transitiveExtensionProperty, object, true, graphs);
		} else {
			HashSet<ARTResource> set = new HashSet<ARTResource>();
			return recursiveInversePropertiesCheckExploration(set, resource, nonTransitiveProperty,
					nonTransitiveInverseProperty, object, graphs);
		}
	}

	/**
	 * method which is invoked by this OWLModel implementation when the complete set of results from a
	 * property which has an inverse has to be obtained. In this case, if a reasoner is not available or if it
	 * is not able to provide owl:inverseOf computation, then an algorithmic solution is adopted to provide
	 * on-the-fly computation for the property passed as an argument.
	 * 
	 * @param resource
	 * @param property
	 * @param inverseProperty
	 * @param graphs
	 * @return
	 * @throws ModelAccessException
	 */
	protected ARTResourceIterator listInversePropertyBoundConcepts(ARTResource resource,
			ARTURIResource property, ARTURIResource inverseProperty, boolean inferred, ARTResource... graphs)
			throws ModelAccessException {

		ARTResourceIterator it = listValuesOfSubjObjPropertyPair(resource, property, inferred, graphs);

		if (!inferred || supportsInverseProperties()) {
			return it;
		} else {
			HashSet<ARTResource> set = new HashSet<ARTResource>();

			while (it.streamOpen()) {
				set.add(it.getNext());
			}
			it.close();

			it = listSubjectsOfPredObjPair(inverseProperty, resource, true, graphs);

			while (it.streamOpen()) {
				set.add(it.getNext());
			}
			it.close();

			return new ARTResourceIteratorImpl(set.iterator());

		}
	}

	/**
	 * method which is invoked by this OWLModel implementation when the complete set of results from a
	 * property which is symmetric has to be obtained. In this case, if a reasoner is not available or if it
	 * is not able to provide owl:Symmetric computation, then an algorithmic solution is adopted to provide
	 * on-the-fly computation for the property passed as an argument.
	 * 
	 * @param resource
	 * @param property
	 * @param graphs
	 * @return
	 * @throws ModelAccessException
	 */
	protected ARTResourceIterator listSymmetricPropertyBoundConcepts(ARTResource resource,
			ARTURIResource property, boolean inferred, ARTResource... graphs) throws ModelAccessException {
		return listInversePropertyBoundConcepts(resource, property, property, inferred, graphs);
	}

	/**
	 * method which is invoked by this OWLModel implementation when the complete set of results from a
	 * transitive property has to be obtained. In this case, if a reasoner is not available or if it is not
	 * able to provide owl:inverseOf computation, then an algorithmic solution is adopted to provide
	 * on-the-fly computation for the property passed as an argument.
	 * 
	 * @param resource
	 * @param property
	 * @param graphs
	 * @return
	 * @throws ModelAccessException
	 */
	protected ARTResourceIterator listTransitivePropertyBoundConcepts(ARTResource resource,
			ARTURIResource property, boolean inferred, ARTResource... graphs) throws ModelAccessException {
		return listTransitivePropertyBoundConcepts(resource, property, property, inferred, graphs);
	}

	/**
	 * as for
	 * {@link #listTransitivePropertyBoundConcepts(ARTResource, ARTURIResource, ARTURIResource, boolean, ARTResource...)}
	 * though the transitive property is the transitive extension of a non-transitive property.<br/>
	 * If no reasoning is asked, the non-transitive property is looked in the concrete triples.<br/>
	 * In case of reasoning (inferred==true), if a reasoner is able to compute it (it has transitive property
	 * reasoning), the transitive property is explored, while if it is not, a recursive exploration of the
	 * non-transitive property is conducted
	 * 
	 * @param resource
	 * @param nonTransitiveProperty
	 * @param transitiveExtensionProperty
	 *            transitive extension of property <code>property</code>
	 * @param graphs
	 * @return
	 * @throws ModelAccessException
	 */
	protected ARTResourceIterator listTransitivePropertyBoundConcepts(ARTResource resource,
			ARTURIResource nonTransitiveProperty, ARTURIResource transitiveExtensionProperty,
			boolean inferred, ARTResource... graphs) throws ModelAccessException {

		if (!inferred)
			return listValuesOfSubjObjPropertyPair(resource, nonTransitiveProperty, inferred, graphs);
		if (supportsTransitiveProperties()) {
			return listValuesOfSubjObjPropertyPair(resource, transitiveExtensionProperty, inferred, graphs);
		} else {
			HashSet<ARTResource> set = new HashSet<ARTResource>();
			recursiveExploration(set, resource, nonTransitiveProperty, graphs);
			return new ARTResourceIteratorImpl(set.iterator());

		}
	}

	/**
	 * 
	 * @param resource
	 * @param nonTransitiveProperty
	 * @param transitiveExtensionProperty
	 *            transitive extension of property <code>property</code>
	 * @param graphs
	 * @return
	 * @throws ModelAccessException
	 */
	protected ARTResourceIterator listTransitiveInversePropertyBoundConcepts(ARTResource resource,
			ARTURIResource nonTransitiveProperty, ARTURIResource nonTransitiveInverseProperty,
			ARTURIResource transitiveExtensionProperty, ARTURIResource transitiveExtensionInverseProperty,
			boolean inferred, ARTResource... graphs) throws ModelAccessException {

		if (!inferred)
			return listValuesOfSubjObjPropertyPair(resource, nonTransitiveProperty, false, graphs);

		if (supportsTransitiveProperties() && supportsInverseProperties()) {
			return listValuesOfSubjObjPropertyPair(resource, transitiveExtensionProperty, true, graphs);
		} else if (supportsTransitiveProperties()) {
			return listInversePropertyBoundConcepts(resource, transitiveExtensionProperty,
					transitiveExtensionInverseProperty, true, graphs);
		} else if (supportsInverseProperties()) {
			return listTransitivePropertyBoundConcepts(resource, nonTransitiveProperty,
					transitiveExtensionProperty, true, graphs);
		} else {
			HashSet<ARTResource> set = new HashSet<ARTResource>();
			recursiveInversePropertiesExploration(set, resource, nonTransitiveProperty,
					nonTransitiveInverseProperty, graphs);
			return new ARTResourceIteratorImpl(set.iterator());

		}
	}

	/**
	 * recursively explore (that is, runs along the transitive closure of) a property and fills the set
	 * <code>set</code> with all the objects of his property
	 * 
	 * @param set
	 * @param resource
	 * @param prop
	 * @param graphs
	 * @throws ModelAccessException
	 */
	private void recursiveExploration(HashSet<ARTResource> set, ARTResource resource, ARTURIResource prop,
			ARTResource... graphs) throws ModelAccessException {
		ARTResourceIterator it = listValuesOfSubjObjPropertyPair(resource, prop, true, graphs);
		while (it.streamOpen()) {
			ARTResource newres = it.getNext();
			if (!set.contains(newres)) {
				set.add(newres);
				recursiveExploration(set, newres, prop, graphs);
			}
		}
		it.close();
	}

	/**
	 * recursively explore (that is, runs along the transitive closure of) a property to find a triple with
	 * object = <code>object</code>
	 * 
	 * @param set
	 * @param resource
	 * @param prop
	 * @param graphs
	 * @throws ModelAccessException
	 */
	private boolean recursiveCheckExploration(HashSet<ARTResource> set, ARTResource resource,
			ARTURIResource prop, ARTResource object, ARTResource... graphs) throws ModelAccessException {
		boolean result = false;
		ARTResourceIterator it = listValuesOfSubjObjPropertyPair(resource, prop, true, graphs);
		while (it.streamOpen() && (result == false)) {
			ARTResource newres = it.getNext();
			if (!set.contains(newres)) {
				if (newres.equals(object)) {
					return true;
				} else {
					set.add(newres);
					result = recursiveCheckExploration(set, newres, prop, object, graphs);
				}
			}
		}
		it.close();
		return result;
	}

	/**
	 * recursively explore (that is, runs along the transitive closure of) a property, which has also a
	 * inverse property. So, for each node A, it explores all nodes reachable from A through property
	 * <code>prop</code> and all nodes reaching A through property <code>inverseProp</code> (the set of them
	 * is computed, that is, no repetitions), then for each of the nodes in the computed set, this process is
	 * applied again on them.
	 * 
	 * @param set
	 * @param resource
	 * @param prop
	 * @param inverseProp
	 * @param graphs
	 * @throws ModelAccessException
	 */
	private void recursiveInversePropertiesExploration(HashSet<ARTResource> set, ARTResource resource,
			ARTURIResource prop, ARTURIResource inverseProp, ARTResource... graphs)
			throws ModelAccessException {
		ARTResourceIterator it = listInversePropertyBoundConcepts(resource, prop, inverseProp, true, graphs);
		while (it.streamOpen()) {
			ARTResource newres = it.getNext();
			if (!set.contains(newres)) {
				set.add(newres);
				recursiveInversePropertiesExploration(set, newres, prop, inverseProp, graphs);
			}
		}
		it.close();
	}

	/**
	 * recursively explore (that is, runs along the transitive closure of) a property, which has also a
	 * inverse property, to find a triple with object == <code>object</code>. So, for each node A, it explores
	 * all nodes reachable from A through property <code>prop</code> and all nodes reaching A through property
	 * <code>inverseProp</code> (the set of them is computed, that is, no repetitions), then for each of the
	 * nodes in the computed set, this process is applied again on them, until <code>object</code> is found or
	 * the search is exhausted.
	 * 
	 * @param set
	 * @param resource
	 * @param prop
	 * @param inverseProp
	 * @param graphs
	 * @throws ModelAccessException
	 */
	private boolean recursiveInversePropertiesCheckExploration(HashSet<ARTResource> set,
			ARTResource resource, ARTURIResource prop, ARTURIResource inverseProp, ARTResource object,
			ARTResource... graphs) throws ModelAccessException {
		System.out
				.println("exploring: " + resource + " on props: " + prop + "|" + inverseProp + "|" + object);
		boolean result = false;
		ARTResourceIterator it = listInversePropertyBoundConcepts(resource, prop, inverseProp, true, graphs);
		while (it.streamOpen() && (result == false)) {
			ARTResource newres = it.getNext();
			System.out.println("next:" + newres);
			if (!set.contains(newres)) {
				if (newres.equals(object)) {
					return true;
				} else {
					set.add(newres);
					result = recursiveInversePropertiesCheckExploration(set, newres, prop, inverseProp,
							object, graphs);
				}
			}
		}
		it.close();
		return result;
	}

	protected class ARTResourceIteratorImpl extends RDFIteratorImpl<ARTResource> implements
			ARTResourceIterator {

		Iterator<ARTResource> it;

		ARTResourceIteratorImpl(Iterator<ARTResource> it) {
			this.it = it;
		}

		public void close() throws ModelAccessException {
		}

		public ARTResource getNext() {
			return it.next();
		}

		public boolean streamOpen() {
			return it.hasNext();
		}

	}

	protected class ARTLiteralIteratorImpl extends RDFIteratorImpl<ARTLiteral> implements ARTLiteralIterator {

		Iterator<ARTLiteral> it;

		ARTLiteralIteratorImpl(Iterator<ARTLiteral> it) {
			this.it = it;
		}

		public void close() throws ModelAccessException {
		}

		public ARTLiteral getNext() {
			return it.next();
		}

		public boolean streamOpen() {
			return it.hasNext();
		}

	}
	
	// TODO Made_By_AlfTurco	
	/**
	     * Add an enumerated class with an identifier (a URI reference) to graphs <code>graphs</code>
	     * @param classURI
	     * @param resources
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	public void addEnumeratedClass(String classURI, ArrayList<ARTNode> resources, ARTResource... graphs)
	            throws ModelUpdateException {
	        if(resources!=null && !resources.isEmpty()){
	            ARTURIResource newProp = baseRep.createURIResource(classURI);
	            baseRep.addTriple(newProp, RDF.Res.TYPE, OWL.Res.CLASS, graphs);
	            ARTBNode currListItem = baseRep.createBNode();
	            baseRep.addTriple(newProp, OWL.Res.ONEOF, currListItem, graphs);

	            ARTBNode nextListItem = null;
	            for(int i = 1; i<=resources.size();i++){
	                baseRep.addTriple(currListItem, RDF.Res.TYPE, RDF.Res.LIST);
	                baseRep.addTriple(currListItem, RDF.Res.FIRST, resources.get(i-1));
	                

	                if (i==resources.size()){
	                    baseRep.addTriple(currListItem, RDF.Res.REST, RDF.Res.NIL);
	                } else {
	                    nextListItem = baseRep.createBNode();
	                    baseRep.addTriple(currListItem, RDF.Res.REST, nextListItem);
	                    currListItem = nextListItem;                
	                }
	            }            
	        }
	        
	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add an anonymous enumerated class to graphs <code>graphs</code>
	     * 
	     * @param id
	     * @param resources
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addOneOf(String BnodeID, ArrayList<ARTNode> resources, ARTResource... graphs)
	            throws ModelUpdateException {
	        if(resources!=null && !resources.isEmpty()){
	            baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.CLASS, graphs);
	            ARTBNode currListItem = baseRep.createBNode();
	            baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.ONEOF, currListItem, graphs);

	            ARTBNode nextListItem = null;
	            for(int i = 1; i<=resources.size();i++){
	                baseRep.addTriple(currListItem, RDF.Res.TYPE, RDF.Res.LIST);
	                baseRep.addTriple(currListItem, RDF.Res.FIRST, resources.get(i-1));

	                if (i==resources.size()){
	                    baseRep.addTriple(currListItem, RDF.Res.REST, RDF.Res.NIL);
	                } else {
	                    nextListItem = baseRep.createBNode();
	                    baseRep.addTriple(currListItem, RDF.Res.REST, nextListItem);
	                    currListItem = nextListItem;                
	                }
	            }            
	        }
	        
	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add a datarange to graphs <code>graphs</code>
	     * @param id
	     * @param resources
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addOneOfDataRange(String BnodeID, ArrayList<ARTLiteral> resources, ARTResource... graphs)
	            throws ModelUpdateException {
	        if(resources!=null && !resources.isEmpty()){
	            baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.DATARANGE, graphs);
	            ARTBNode currListItem = baseRep.createBNode();
	            baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.ONEOF, currListItem, graphs);

	            ARTBNode nextListItem = null;
	            for(int i = 1; i<=resources.size();i++){
	                baseRep.addTriple(currListItem, RDF.Res.TYPE, RDF.Res.LIST);
	                baseRep.addTriple(currListItem, RDF.Res.FIRST, resources.get(i-1));

	                if (i==resources.size()){
	                    baseRep.addTriple(currListItem, RDF.Res.REST, RDF.Res.NIL);
	                } else {
	                    nextListItem = baseRep.createBNode();
	                    baseRep.addTriple(currListItem, RDF.Res.REST, nextListItem);
	                    currListItem = nextListItem;                
	                }
	            }            
	        }
	        
	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add an anonymous class as a restriction on range (All Values) of a property to <code>graphs</code> 
	     * 
	     * @param ID
	     * @param property
	     * @param resource
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addRestrictionOnPropertyAllValuesFrom(String BnodeID, ARTURIResource property, ARTResource resource, ARTResource... graphs)
	            throws ModelUpdateException {

	        baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.RESTRICTION, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.ONPROPERTY, property, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.ALLVALUESFROM, resource, graphs);

	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add an anonymous class as a restriction on range (Some Values) of a property to <code>graphs</code> 
	     * @param ID
	     * @param property
	     * @param resource
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addRestrictionOnPropertySomeValuesFrom(String BnodeID, ARTURIResource property, ARTResource resource, ARTResource... graphs)
	            throws ModelUpdateException {
	        baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.RESTRICTION, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.ONPROPERTY, property, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.SOMEVALUESFROM, resource, graphs);

	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add an anonymous class as a restriction on range (Has Value) of a property to <code>graphs</code> 
	     * 
	     * @param ID
	     * @param property
	     * @param resourceOrLiteral
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addRestrictionOnPropertyHasValue(String BnodeID, ARTURIResource property, ARTNode resourceOrLiteral, ARTResource... graphs)
	            throws ModelUpdateException {
	        baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.RESTRICTION, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.ONPROPERTY, property, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.HASVALUE, resourceOrLiteral, graphs);
	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add an anonymous class as a restriction on the minimum cardinality of property to <code>graphs</code>
	     * 
	     * @param ID
	     * @param property
	     * @param literal
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addRestrictionOnCardinalityMinCardinality(String BnodeID, ARTURIResource property, String literal, ARTResource... graphs)
	            throws ModelUpdateException {
	        baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.RESTRICTION, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.ONPROPERTY, property, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.MINCARDINALITY, baseRep.createLiteral(literal, XmlSchema.Res.NON_NEGATIVE_INTEGER), graphs);
	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add an anonymous class as a restriction on the maximum cardinality of property to <code>graphs</code>
	     * 
	     * @param ID
	     * @param property
	     * @param literal
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addRestrictionOnCardinalityMaxCardinality(String BnodeID, ARTURIResource property, String literal, ARTResource... graphs)
	            throws ModelUpdateException {
	        baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.RESTRICTION, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.ONPROPERTY, property, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.MAXCARDINALITY, baseRep.createLiteral(literal, XmlSchema.Res.NON_NEGATIVE_INTEGER), graphs);
	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add an anonymous class as a restriction on the cardinality of property to <code>graphs</code>
	     * 
	     * @param ID
	     * @param property
	     * @param literal
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addRestrictionOnCardinalityCardinality(String BnodeID, ARTURIResource property, String literal, ARTResource... graphs)
	            throws ModelUpdateException {
	        baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.RESTRICTION, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.ONPROPERTY, property, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.CARDINALITY, baseRep.createLiteral(literal, XmlSchema.Res.NON_NEGATIVE_INTEGER), graphs);
	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add an anonymous class as intersection of a set of resources to <code>graphs</code>
	     * 
	     * @param ID
	     * @param descriptions
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addIntersectionOf(String BnodeID, ArrayList<ARTResource> descriptions, ARTResource... graphs)
	            throws ModelUpdateException {
	        if(descriptions!=null && !descriptions.isEmpty()){
	            baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.CLASS, graphs);
	            ARTBNode currListItem = baseRep.createBNode();
	            baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.INTERSECTIONOF, currListItem, graphs);


	            ARTBNode nextListItem = null;
	            for(int i = 1; i<=descriptions.size();i++){
	                baseRep.addTriple(currListItem, RDF.Res.TYPE, RDF.Res.LIST);
	                baseRep.addTriple(currListItem, RDF.Res.FIRST, descriptions.get(i-1));

	                if (i==descriptions.size()){
	                    baseRep.addTriple(currListItem, RDF.Res.REST, RDF.Res.NIL);
	                } else {
	                    nextListItem = baseRep.createBNode();
	                    baseRep.addTriple(currListItem, RDF.Res.REST, nextListItem);
	                    currListItem = nextListItem;                
	                }
	            }            
	        }
	        
	    }
	    
	// TODO Made_By_AlfTurco			
	    /**
	     * Add an anonymous class as the complement of the specified resource to <code>graphs</code>
	     * 
	     * @param ID
	     * @param description
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addComplementOf(String BnodeID, ARTResource description, ARTResource... graphs)
	            throws ModelUpdateException {
	        baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.CLASS, graphs);
	        baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.COMPLEMENTOF, description, graphs);
	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add an anonymous class as union of a set of resources to <code>graphs</code>
	     * 
	     * @param ID
	     * @param descriptions
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addUnionOf(String BnodeID, ArrayList<ARTResource> descriptions, ARTResource... graphs)
	            throws ModelUpdateException {
	        if(descriptions!=null && !descriptions.isEmpty()){
	            baseRep.addTriple(baseRep.createBNode(BnodeID), RDF.Res.TYPE, OWL.Res.CLASS, graphs);
	            ARTBNode currListItem = baseRep.createBNode();
	            baseRep.addTriple(baseRep.createBNode(BnodeID), OWL.Res.UNIONOF, currListItem, graphs);

	            ARTBNode nextListItem = null;
	            for(int i = 1; i<=descriptions.size();i++){
	                baseRep.addTriple(currListItem, RDF.Res.TYPE, RDF.Res.LIST);
	                baseRep.addTriple(currListItem, RDF.Res.FIRST, descriptions.get(i-1));

	                if (i==descriptions.size()){
	                    baseRep.addTriple(currListItem, RDF.Res.REST, RDF.Res.NIL);
	                } else {
	                    nextListItem = baseRep.createBNode();
	                    baseRep.addTriple(currListItem, RDF.Res.REST, nextListItem);
	                    currListItem = nextListItem;                
	                }
	            }            
	        }
	        
	    }

	// TODO Made_By_AlfTurco	
	    /**
	     * Add a named equivalent class of the specified resource to <code>graphs</code>
	     * 
	     * @param StringURI
	     * @param equivalentClass
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addEquivalentClass(String classURI, ARTResource equivalentClass, ARTResource... graphs) throws ModelUpdateException {
	        baseRep.addTriple(baseRep.createURIResource(classURI), RDF.Res.TYPE, OWL.Res.CLASS, graphs);
	        baseRep.addTriple(baseRep.createURIResource(classURI), OWL.Res.EQUIVALENTCLASS, equivalentClass, graphs);
	    }

	    
	// TODO Made_By_AlfTurco			
	    /**
	     * Add an named subclass of the specified resource to <code>graphs</code>
	     * 
	     * @param StringURI
	     * @param subClass
	     * @param graphs
	     * @throws ModelUpdateException 
	     */
	    public void addSubClassOf(String classURI, ARTResource subClass, ARTResource... graphs) throws ModelUpdateException {
	            baseRep.addTriple(baseRep.createURIResource(classURI), RDF.Res.TYPE, OWL.Res.CLASS, graphs);
	            baseRep.addTriple(baseRep.createURIResource(classURI), RDFS.Res.SUBCLASSOF, subClass, graphs);
	    }
	    
	// TODO Made_By_AlfTurco			
	    /**
		 * recursively explore (that is, runs along the transitive closure of) a property and fills the set
		 * <code>set</code> with all the objects which are blank node of his property
		 * 
		 * @param set
		 * @param resource
		 * @param prop
		 * @param graphs
		 * @throws ModelAccessException
		 */
		public void recursiveBNodeExploration(HashSet<ARTResource> set, ARTResource resource, ARTURIResource prop,
				ARTResource... graphs) throws ModelAccessException {
		    //ARTResourceIterator it = listValuesOfSubjObjPropertyPair(resource, prop, true, graphs);
		    ARTNodeIterator it = listValuesOfSubjPredPair(resource,prop,false,graphs);
			while (it.hasNext()) {
				ARTNode newnode = it.getNext();
				if(newnode.isLiteral()) continue;
				else {
				    ARTResource newres = newnode.asResource();
				    if (!set.contains(newres) && newres.isBlank()) {
					set.add(newres);
					recursiveBNodeExploration(set, newres, prop, graphs);
				    }
				}
			}
			it.close();
		}

}
